﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.IO.Compression;
using System.Drawing.Drawing2D;
using System.Xml;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;




namespace Editeur_map
{
    public partial class editeur : Form
    {

        #region variables

        // listes d'images :
        string[] path_background_array = new string[50];
        string[] path_element_array = new string[50];
        string[] path_map_array = new string[50];
        int[] quadrillage_multiples = new int[100];
        string path_back = "";
        string path_elt = "";
        string path_map = "";


        // Liste des éléments placés sur la map
        List<Node> decor_list = new List<Node>();
        List<Node> delete_decor = new List<Node>();
        List<Background> background_list = new List<Background>();



        // graphics

        private Graphics graph, preview;
        private Bitmap bmp, bmp_preview;

        // position initiale
        private int x_back, y_back, x_decalage, y_decalage;

        //paramètres
        int vitesse_defilement = 35;
        int quadrillage = 35;



        #endregion

        #region Editeur

        public editeur()
        {
            InitializeComponent();

            x_back = 0;
            y_back = 0;

            bmp = new Bitmap(map.Width, map.Height);
            bmp_preview = new Bitmap(element_view.Width, element_view.Height);

            graph = Graphics.FromImage(bmp);
            preview = Graphics.FromImage(bmp_preview);

            up.Enabled = false;
            down.Enabled = false;
            right.Enabled = false;
            left.Enabled = false;
            map.Enabled = false;
            load_map.Enabled = false;



            x_decalage = 0;
            y_decalage = 0;
        }

        private void editeur_Load(object sender, EventArgs e)
        {
            // ini de la picture_box
            graph.Clear(Color.Gray);
            map.Image = bmp;
            // ini element_view
            preview.Clear(Color.Gray);
            element_view.Image = bmp_preview;


            //parser les sous-dossier pour trouver les éléments dispo
            //dossiers : "backgrounds" ; "elements"
            //------------------\\
            // Les éléments :   ||
            //------------------//
            refresh_elts_listbox();

            //------------------\\
            // Les backgrounds :||
            //------------------//
            refresh_background_listbox();

            //--------------------\\
            // Les maps récentes :||
            //--------------------//
            refresh_recent_map();

            quad_multiple(ref quadrillage_multiples);
            Background background = new Background();
            background.function = "background";
            background_list.Add(background);
        }

        private void map_Click(object sender, EventArgs e)
        {

            Point mouse_pos = ((MouseEventArgs)e).Location;
            mouse_pos = normalize(mouse_pos);


            if (((MouseEventArgs)e).Button == MouseButtons.Left)
            {
                createTile(mouse_pos);
            }
            else if (((MouseEventArgs)e).Button == MouseButtons.Right)
            {
                removeTile(mouse_pos);
            }


            maj_map(sender, e);
        }

        private void removeTile(Point pos)
        {
            Node sup = new Node();

            foreach (Node node in decor_list)
            {
                if ((pos.X == (node.pos.X - x_decalage))
                    && (pos.Y == (node.pos.Y - y_decalage)))
                    sup = node;
            }
           
            decor_list.Remove(sup);
        }

        private void createTile(Point pos)
        {
            if (decor_list.Count > 0)
                removeTile(pos);

            //création de la nouvelle node
            Node node = new Node();
            node.pos.X = pos.X + x_decalage;
            node.pos.Y = pos.Y + y_decalage;
            node.path_elt = path_elt;
            node.x_decalage = x_decalage;
            node.y_decalage = y_decalage;
            decor_list.Add(node);
        }

        private void quit_Click(object sender, EventArgs e)
        {
            // proposer sauvegarde de la map en cours :
            // FIX ME

            // sauvegarder changements background_listbox
            // FIX ME

            // sauvegarder changements elements_listbox
            // FIX ME

            // Quitter l'application
            this.Close();

        }

        private string pathToName(string path)
        {
            int i = 0;
            string res = "";

            while ((path[i] != '/') && (path[i] != '\\'))
            {
                i++;
            }

            i++;
            while (path[i] != '.')
            {
                res += path[i];
                i++;
            }
            return res;
        }

        private void elements_listbox_SelectedIndexChanged(object sender, EventArgs e)
        {
            int i;
            string elt;

            if (!(map.Enabled) && up.Enabled)
                map.Enabled = true;


            clear_preview_Click(sender, e);

            i = elements_listbox.SelectedIndex;
            elt = (string)elements_listbox.SelectedItem;
            path_elt = "elements/" + (string)elt + ".png";

            Image image = Image.FromFile(path_elt);
            preview.DrawImage(image, new Rectangle(0, 0, element_view.Width, element_view.Height));
            element_view.Image = bmp_preview;
        }

        private void recent_map_SelectedIndexChanged(object sender, EventArgs e)
        {
            // fonction gérant la 3ème listbox (pour les map dispo)
            int i;
            string map;

            if (!(load_map.Enabled))
                load_map.Enabled = true;

            i = recent_map.SelectedIndex;
            map = (string)recent_map.SelectedItem;
            path_map = "map/" + map + ".rab";

        }

        private void background_listbox_SelectedIndexChanged(object sender, EventArgs e)
        {
            int i;
            string elt;

            //dévérouille les flèches de défilement
            if (!(up.Enabled))
            {
                up.Enabled = true;
                down.Enabled = true;
                right.Enabled = true;
                left.Enabled = true;
            }


            //clear le graph
            clear_Click(sender, e);

            //determine l'image à charger
            i = background_listbox.SelectedIndex;
            elt = (string)background_listbox.SelectedItem;
            path_back = "backgrounds/" + background_listbox.SelectedItem.ToString() + ".png";

            background_list[0].path_back = path_back;

            Image image = Image.FromFile(path_back);
            graph.DrawImage(image, new Rectangle(0, 0, map.Width, map.Height));
            map.Image = bmp;

            maj_map(sender, e);
        }

        private void lock_backlist_Click(object sender, EventArgs e)
        {
            if (background_listbox.Enabled)
                background_listbox.Enabled = false;
            else
                background_listbox.Enabled = true;
        }

        private void clear_Click(object sender, EventArgs e)
        {

            graph.Clear(Color.Gray);
            map.Image = bmp;
        }

        private void clear_preview_Click(object sender, EventArgs e)
        {
            preview.Clear(Color.Gray);
            element_view.Image = bmp_preview;
        }

        // Gestion du défilement du background
        private void right_Click(object sender, EventArgs e)
        {
            x_back = x_back - vitesse_defilement;
            x_decalage = x_decalage + vitesse_defilement;
            maj_map(sender, e);
        }

        private void left_Click(object sender, EventArgs e)
        {
            x_back = x_back + vitesse_defilement;
            x_decalage = x_decalage - vitesse_defilement;
            maj_map(sender, e);
        }

        private void up_Click(object sender, EventArgs e)
        {
            y_back = y_back + vitesse_defilement;
            y_decalage = y_decalage - vitesse_defilement;
            maj_map(sender, e);
        }

        private void down_Click(object sender, EventArgs e)
        {
            y_back = y_back - vitesse_defilement;
            y_decalage = y_decalage + vitesse_defilement;
            maj_map(sender, e);
        }

        private void maj_map(object sender, EventArgs e)
        {
            try
            {
                clear_Click(sender, e);

                position.Text = Convert.ToString(x_decalage / quadrillage) + "/" + Convert.ToString(-(y_decalage / quadrillage));
                if (path_back == "")
                    path_back = background_list[0].path_back;

                Image image_back = Image.FromFile(path_back);
                graph.DrawImage(image_back, new Rectangle(0, 0, map.Width, map.Height));

            }
            catch
            {

            }
            // dessin des nodes

            foreach (Node node in decor_list)
            {
                Image element = Image.FromFile(node.path_elt);
                graph.DrawImage(element, new Point(node.pos.X - x_decalage,
                    node.pos.Y - y_decalage));
            }

            // quadrillage


            int largeur = map.Width;
            while (largeur > 0)
            {
                largeur -= quadrillage;
                graph.DrawLine(new Pen(Color.Gray, 0.5f), new Point(largeur, 0),
                    new Point(largeur, map.Height - 1));

            }

            int hauteur = map.Height;
            while (hauteur > 0)
            {
                hauteur -= quadrillage;
                graph.DrawLine(new Pen(Color.Gray, 0.5f), new Point(0, hauteur),
                    new Point(map.Width - 1, hauteur));
            }

            map.Image = bmp;
        }

        private void previous_action_Click(object sender, EventArgs e)
        {
            if (decor_list.Count > 0)
            {
                delete_decor.Add(decor_list[decor_list.Count - 1]);
                decor_list.RemoveAt(decor_list.Count - 1);

                maj_map(sender, e);
            }
        }

        private void next_action_Click(object sender, EventArgs e)
        {
            if (delete_decor.Count > 0)
            {
                decor_list.Add(delete_decor[delete_decor.Count - 1]);
                delete_decor.RemoveAt(delete_decor.Count - 1);

                maj_map(sender, e);
            }
        }

        private void reset_map_Click(object sender, EventArgs e)
        {
            x_decalage = y_decalage = 0;
            clear_Click(sender, e);
            decor_list.Clear();
            delete_decor.Clear();
            background_list.Clear();

            path_back = "";

            Background background = new Background();
            background.function = "background";
            background.path_back = "";

            background_list.Add(background);

            path_elt = "";
            up.Enabled = false;
            down.Enabled = false;
            right.Enabled = false;
            left.Enabled = false;
            map.Enabled = false;


        }

        private void load_map_Click(object sender, EventArgs e)
        {
            x_decalage = y_decalage = 0;
            try
            {
                if (path_map != "")
                {
                    reset_map_Click(sender, e);
                    clear_Click(sender, e);
                    decor_list.Clear();
                    delete_decor.Clear();
                    background_list.Clear();

                    FileStream fs = new FileStream(path_map, FileMode.Open);
                    BinaryFormatter bf = new BinaryFormatter();
                    Map_State mymap = new Map_State();
                    mymap = (Map_State)bf.Deserialize(fs);
                    decor_list = mymap.list_node;
                    background_list = mymap.background_list;
                    addContent(mymap);

                    fs.Close();



                    maj_map(sender, e);
                }
            }
            catch 
            {
                path_back = "fatal_error.png";
                graph.DrawImage(Image.FromFile("fatal_error.png"), new Rectangle(0, 0, map.Width, map.Height));
                map.Image = bmp;
            }



            if (!(up.Enabled))
            {
                up.Enabled = true;
                down.Enabled = true;
                right.Enabled = true;
                left.Enabled = true;
            }


        }

        private void print_screen_Click(object sender, EventArgs e)
        {
            if (!(Directory.Exists("screen")))
                Directory.CreateDirectory("screen");

            if (path_back != "")
            {
                Image image = Image.FromFile(path_back);
                graph.DrawImage(image, new Point(x_back, y_back));
            }


            foreach (Node node in decor_list)
            {
                Image element = Image.FromFile(node.path_elt);
                graph.DrawImage(element, new Point(node.pos.X - x_decalage,
                    node.pos.Y - y_decalage));
            }

            FileStream fs = new FileStream("screen/test.jpeg", FileMode.OpenOrCreate);
            string path_screen = "screen/" + DeleteSpace((DateTime.Now.ToString())) + ".png";
            bmp.Save("screen/" + DeleteSpace((DateTime.Now.ToString())) + ".png");
            fs.Close();
        }

        // delete les charactères non-acceptés dans un nom de ficher
        private string DeleteSpace(string s)
        {
            string res = "";

            for (int i = 0; i < s.Length; i++)
            {
                if (s[i] == '/' || s[i] == '\\' || s[i] == ':')
                    res += '-';
                else
                    res += s[i];
            }
            return res;
        }

        private void delete_elts_Click(object sender, EventArgs e)
        {
            decor_list.Clear();
            delete_decor.Clear();

            maj_map(sender, e);
        }

        private void delete_map_Click(object sender, EventArgs e)
        {
            try
            {
                File.Delete(path_map);
                refresh_recent_map();
            }
            catch 
            {

            }
        }

        private void refresh_recent_map()
        {
            if (!Directory.Exists("map"))
                Directory.CreateDirectory("map");


            recent_map.Items.Clear();
            path_map_array.Initialize();
            path_map_array = Directory.GetFiles("map");
            for (int i = 0; i < path_map_array.Length; i++)
            {
                recent_map.Items.Add(pathToName(path_map_array[i]));

            }

        }

        private void refresh_background_listbox()
        {
            if (!Directory.Exists("backgrounds"))
                Directory.CreateDirectory("backgrounds");


            background_listbox.Items.Clear();
            path_background_array.Initialize();
            path_background_array = Directory.GetFiles("backgrounds");
            for (int i = 0; i < path_background_array.Length; i++)
            {
                background_listbox.Items.Add(pathToName(path_background_array[i]));

            }

        }

        private void refresh_elts_listbox()
        {
            if (!Directory.Exists("elements"))
                Directory.CreateDirectory("elements");

            elements_listbox.Items.Clear();
            path_element_array.Initialize();
            path_element_array = Directory.GetFiles("elements");
            for (int i = 0; i < path_element_array.Length; i++)
            {
                elements_listbox.Items.Add(pathToName(path_element_array[i]));
            }
        }

        private Point normalize(Point point)
        {
            int x, y, i;            
            x = point.X;
            y = point.Y;


            i = 0;
            while (x > quadrillage_multiples[i])
            {
                i++;
            }
            if (i > 0)
                x = quadrillage_multiples[i - 1];
            else
                x = quadrillage_multiples[0];

            i = 0;
            while (y > quadrillage_multiples[i])
            {
                i++;
            }
            if (i > 0)
                y = quadrillage_multiples[i - 1];
            else
                y = quadrillage_multiples[0];



            Point p = new Point(x, y);
            return p;
        }

        public void quad_multiple(ref int[] tab)
        {
            tab[0] = 0;
            for (int i = 1; i < tab.Length; i++)
            {
                tab[i] = tab[i - 1] + quadrillage;
            }
        }

        private void map_exporter_Click(object sender, EventArgs e)
        {
            Map_State mymap = new Map_State();
            mymap.list_node = decor_list;
            mymap.background_list = background_list;

            save_box.ShowDialog();
            string path_export = save_box.FileName;
            if (path_export != "")
            {
                string previous_path = path_export;
                List<TileImage> fichier_map = new List<TileImage>();
                //Directory.CreateDirectory(path_export);
                //SaveXml(path_export + "/" + "map_info.xml");


                //File.Copy(decor_list[1].path_elt, path_export + "/" + "test.png");
                foreach (Background back in background_list)
                {
                    TileImage image = new TileImage();
                    image.image = Image.FromFile(back.path_back);
                    image.name = pathToName(back.path_back);                    
                    image.function = back.function;

                    if (!fichier_map.Contains(image))                 
                        fichier_map.Add(image);
                        
                    
                }

                foreach (Node node in decor_list)
                {
                    TileImage image = new TileImage();
                    image.image = Image.FromFile(node.path_elt);
                    image.name = pathToName(node.path_elt);
                    image.function = "tile";

                    if (!fichier_map.Contains(image))   
                        fichier_map.Add(image);          
                }


                mymap.list_image = fichier_map;

                FileStream fs = new FileStream(path_export + ".rab", FileMode.OpenOrCreate);

                BinaryFormatter bf = new BinaryFormatter();
                try
                {
                    bf.Serialize(fs, mymap);

                }
                catch (Exception ex)
                {
                    path_back = "fatal_error.png";
                    graph.DrawImage(Image.FromFile("fatal_error.png"), new Rectangle(0, 0, map.Width, map.Height));
                    map.Image = bmp;

                    FileStream s = new FileStream("error.txt", FileMode.OpenOrCreate);
                    StreamWriter sr = new StreamWriter(s);
                    sr.WriteLine(ex);
                    sr.Close();
                }
                finally
                {
                    fs.Close();
                }

                refresh_recent_map();
            }
        }

        private void open_map_Click(object sender, EventArgs e)
        {
            open_box.ShowDialog();
            string path_open = open_box.FileName;
            x_decalage = y_decalage = 0;

            try
            {
                if (path_open != "")
                {
                    reset_map_Click(sender, e);
                    clear_Click(sender, e);
                    decor_list.Clear();
                    delete_decor.Clear();
                    background_list.Clear();

                    FileStream fs = new FileStream(path_open, FileMode.Open);
                    BinaryFormatter bf = new BinaryFormatter();
                    Map_State mymap = new Map_State();
                    mymap = (Map_State)bf.Deserialize(fs);
                    decor_list = mymap.list_node;
                    background_list = mymap.background_list;
                    addContent(mymap);

                    fs.Close();



                    maj_map(sender, e);
                }
            }
            catch 
            {
                path_back = "fatal_error.png";
                graph.DrawImage(Image.FromFile(path_back), new Rectangle(0, 0, map.Width, map.Height));
                map.Image = bmp;
            }



            if (!(up.Enabled))
            {
                up.Enabled = true;
                down.Enabled = true;
                right.Enabled = true;
                left.Enabled = true;
            }


        }

        private void recentrer_button_Click(object sender, EventArgs e)
        {
            x_decalage = y_decalage = 0;
            maj_map(sender, e);
        }

        
        private void addContent(Map_State mymap)
        {
            int i = 0;
            foreach (TileImage image in mymap.list_image)
            {
                if (i == 0)
                {
                    FileStream fs = new FileStream("backgrounds/" + image.name + ".png" ,
                        FileMode.OpenOrCreate);
                    image.image.Save(fs, ImageFormat.Png);
                    fs.Close();
                }
                else
                {
                    FileStream fs = new FileStream("elements/" + image.name + ".png",
                        FileMode.OpenOrCreate);
                    image.image.Save(fs, ImageFormat.Png);
                    fs.Close();
                }
                i++;
            }
        }
        

        #endregion

        // Useless avec le format .rab
        #region XML
        //-------------------------------------\\
        //  Fonction de gestion des fichiers XML \\
        //-----------------------------------------\\

        //a faire : laod map ; save map



        private void SaveXml(string path)
        {
            FileStream fs = new FileStream(path, FileMode.OpenOrCreate);
            XmlSerializer sr = new XmlSerializer(typeof(List<Node>));
            sr.Serialize(fs, decor_list);
            fs.Close();
        }

        private void LoadXml2(string path)
        {
            FileStream fs = new FileStream(path, FileMode.OpenOrCreate);
            XmlSerializer sr = new XmlSerializer(typeof(List<Node>));
            decor_list = (List<Node>)sr.Deserialize(fs);
            fs.Close();
        }

        #endregion

























    }
}
